package main

import (
	"bytes"
	"fmt"
	"github.com/aliyun/aliyun-oss-go-sdk/oss"
	"github.com/nfnt/resize"
	uuid "github.com/satori/go.uuid"
	"image"
	"image/jpeg"
	"image/png"
	"net/http"
	"net/url"
	"os"
	"strings"
)

const (
	ENDPOINT           = "oss-cn-beijing.aliyuncs.com"
	ACCESS_KEY_ID      = "LTAI4G6LUDduWUyHsj5xZNjf"
	ACCESS_KEY_SECRET  = "gmUfkSG73idCxCjW4kBfvviQNSc8lR"
	BUCKET_NAME        = "wwycda"
	TEMP_DIR           = "D://uploadFile/"
	SMALL_IMAGE_WIDHT  = 300
	SMALL_IMAGE_HEIGHT = 300
)

var bucket *oss.Bucket

func init() {
	client, err := oss.New(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET)
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	// 获取存储空间。
	bucket, err = client.Bucket(BUCKET_NAME)
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}
	// 创建临时文件目录
	os.MkdirAll(TEMP_DIR, os.ModePerm)

}

func main() {
	fmt.Println(oss.Version)
	mux := http.NewServeMux()
	mux.HandleFunc("/imageproxy", func(writer http.ResponseWriter, request *http.Request) {
		err := request.ParseForm()
		if err != nil {
			fmt.Fprintln(writer, err.Error())
			writer.WriteHeader(http.StatusInternalServerError)
			return
		}
		// 解析oss地址
		u := request.Form.Get("url")
		fmt.Println(u)
		ossObjectName, hostName, err := resolveOssObject(u)
		if err != nil {
			fmt.Fprintln(writer, err.Error())
			writer.WriteHeader(http.StatusInternalServerError)
			return
		}
		fmt.Println(ossObjectName, hostName)
		// 解析小图地址
		smallOssObjectName := generateSmallImageOssObject(ossObjectName)
		fmt.Println(smallOssObjectName)
		// 判断小图存不存在
		isExist, err := bucket.IsObjectExist(smallOssObjectName)
		if err != nil {
			fmt.Fprintln(writer, err.Error())
			writer.WriteHeader(http.StatusInternalServerError)
			return
		}
		// 如果存在，直接返回对应链接
		smallOssUrl := "http://" + hostName + "/" + smallOssObjectName
		if isExist {
			http.Redirect(writer, request, smallOssUrl, http.StatusFound)
			return
		}
		// 如果不存在，则下载图片到本地，并压缩后上传到对应oss对象
		// 然后返回对应链接
		err = compressAndUpload(ossObjectName, smallOssObjectName)
		if err != nil {
			fmt.Fprintln(writer, err.Error())
			writer.WriteHeader(http.StatusInternalServerError)
			return
		}
		http.Redirect(writer, request, smallOssUrl, http.StatusFound)
		return
	})
	http.ListenAndServe(":8080", mux)
}

// 解析出oss地址
func resolveOssObject(u string) (string, string, error) {
	r, err := url.Parse(u)
	if err != nil {
		return "", "", err
	}
	p := r.Path
	if strings.HasPrefix(p, "/") {
		p = p[1:len(p)]
	}
	return p, r.Host, nil
}

// 解析出文件后缀
func resolverSuffix(u string) string {
	return u[strings.LastIndex(u, "."):len(u)]
}

// 生成小图的oss图片对象
func generateSmallImageOssObject(ossObject string) string {
	lastDotIndex := strings.LastIndex(ossObject, ".")
	resultObjectName := ossObject[0:lastDotIndex] + "_small" + resolverSuffix(ossObject)
	return resultObjectName
}

// 压缩并上传
func compressAndUpload(bigOssObject string, smallOssObject string) error {
	tempFilePath := getTempFilePath(bigOssObject)
	err := bucket.GetObjectToFile(bigOssObject, tempFilePath)
	if err != nil {
		return err
	}
	tempFile, err := os.Open(tempFilePath)
	defer func() {
		tempFile.Close()
		os.Remove(tempFile.Name())
	}()
	if err != nil {
		return err
	}
	img, _, err := image.Decode(tempFile)
	if err != nil {
		return err
	}
	img = resize.Thumbnail(SMALL_IMAGE_WIDHT, SMALL_IMAGE_HEIGHT, img, resize.NearestNeighbor)

	fileSuffix := resolverSuffix(smallOssObject)

	buffer := bytes.NewBuffer([]byte{})
	if fileSuffix == "png" {
		err = png.Encode(buffer, img)
		if err != nil {
			return err
		}
	} else {
		err = jpeg.Encode(buffer, img, nil)
		if err != nil {
			return err
		}
	}

	err = bucket.PutObject(smallOssObject, buffer)

	return err
}

// 获取临时文件目录
func getTempFilePath(ossObject string) string {
	suffix := ossObject[strings.LastIndex(ossObject, "."):len(ossObject)]
	fmt.Println("suffix:", suffix)
	u := uuid.NewV1().String()
	return TEMP_DIR + u + suffix
}
